package zhongbo.java.air.listener;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.DeserializationFeature;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import zhongbo.java.air.config.RedisListenerConfig;
import zhongbo.java.air.dto.AirFlightPathDto;

import java.math.BigDecimal;
import java.util.Date;

@Component
@Slf4j
public class RedisSubscribeLogChannelListener implements MessageListener {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private RedisLogChaneIPublisher redisLogChanelPublisher;

    public RedisSubscribeLogChannelListener(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
        // 配置ObjectMapper忽略未知属性
        this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    @Override
    public void onMessage(Message message, byte[] bytes) {
        String channel = new String(message.getChannel()); // 获取频道名称
        String rawMsg = new String(message.getBody());
        log.info("接收到频道 [{}] 原始航迹数据: {}", channel, rawMsg);

        // 忽略包含action字段的消息体
        if (rawMsg.contains("\"action\"")) {
            log.info("忽略包含action字段的消息体: {}", rawMsg);
            return;
        }

        AirFlightPathDto flightPath = convertToFlightPath(rawMsg);
        if (flightPath != null) {
            if (flightPath.getIcao_code() == null || flightPath.getIcao_code().isEmpty()) {
                log.info("icao_code 为空，忽略该消息体: {}", rawMsg);
                return;
            }
            log.info("接收到频道 [{}] 装换后的航迹数据: {}", channel, flightPath);
        }
        //flightPath转换为json
        String json = null;
        try {
            json = objectMapper.writeValueAsString(flightPath);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        log.info("转换后的JSON数据: {}", json); // 输出转换后的JSON数据
        try {
            redisLogChanelPublisher.publish(RedisListenerConfig.INJEST_FLIGHT_PATH, json);
        } catch (RedisSystemException e) {
            log.error("Redis系统异常: {}", json, e);
        }
    }

    private AirFlightPathDto convertToFlightPath(String rawMsg) {
        AirFlightPathDto flightPath = new AirFlightPathDto();
        if (rawMsg == null || rawMsg.isEmpty()){
            throw new RuntimeException("原始航迹数据为空");
        }
        JSONObject jsonObject = JSONUtil.parseObj(rawMsg);

        if (jsonObject.getStr("icao") == null){
            flightPath.setIcao_code("");
        } else {
            String icaoCode = jsonObject.getStr("icao");
            flightPath.setIcao_code(icaoCode);
        }

        if (jsonObject.getJSONArray("trace") == null || jsonObject.getJSONArray("trace").isEmpty()){
            throw new RuntimeException("原始航迹数据trace为空");
        }
        JSONArray jsonArray = jsonObject.getJSONArray("trace");

        if (jsonArray.get(0) == null){
            throw new RuntimeException("原始航迹数据trace[0]为空");
        }

        String timestampStr = jsonObject.getStr("timestamp");
        if (timestampStr != null) {
            try {
                long timestampLong;
                if (timestampStr.contains("T")) {
                    // 处理ISO 8601格式的时间戳
                    if (!timestampStr.contains(".")) {
                        timestampStr += ".000"; // 如果没有毫秒部分，补全为000
                    } else {
                        // 如果有毫秒部分，确保毫秒部分为3位
                        String[] parts = timestampStr.split("\\.");
                        if (parts.length > 1 && parts[1].length() < 3) {
                            timestampStr = parts[0] + "." + String.format("%-3s", parts[1]).replace(' ', '0');
                        }
                    }
                    Date timestampDate = DateUtil.parse(timestampStr);
                    timestampLong = timestampDate.getTime();
                } else if (timestampStr.length() == 13) {
                    // 处理时间戳格式（假设为毫秒级时间戳）
                    timestampLong = Long.parseLong(timestampStr);
                } else {
                    // 处理浮点数格式的时间戳
                    double timestampDouble = Double.parseDouble(timestampStr);
                    timestampLong = (long) (timestampDouble * 1000); // 将秒转换为毫秒
                }

                // 获取 trace[0] 的值
                Object firstElement = jsonArray.get(0);
                double trace0 = 0.0;
                if (firstElement instanceof BigDecimal) {
                    trace0 = ((BigDecimal) firstElement).doubleValue();
                } else if (firstElement instanceof Double) {
                    trace0 = (Double) firstElement;
                } else {
                    // 尝试将firstElement转换为Double
                    try {
                        trace0 = Double.parseDouble(firstElement.toString());
                    } catch (NumberFormatException e) {
                        throw new RuntimeException("trace[0]类型不合法，应为数字类型", e);
                    }
                }

                // 计算最终的时间戳
                long finalTimestampLong = timestampLong + (long) (trace0 * 1000); // trace[0] 是秒，需要转换为毫秒
                Date finalTimestamp = new Date(finalTimestampLong);
                flightPath.setTimestamp(finalTimestamp);
            } catch (Exception e) {
                throw new RuntimeException("无法解析timestamp字段: " + timestampStr, e);
            }
        } else {
            throw new RuntimeException("原始航迹数据timestamp为空");
        }

        Object latitudeObj = jsonArray.get(1);
        if (latitudeObj instanceof Number) { // 检查是否为数值类型（包括BigDecimal）
            Double latitude = ((Number) latitudeObj).doubleValue();
            flightPath.setLatitude(latitude);
        } else {
            throw new RuntimeException("纬度字段类型错误，应为数值类型");
        }

        Object longitudeObj = jsonArray.get(2);
        if (longitudeObj instanceof Number) { // 检查是否为数值类型（包括BigDecimal）
            Double longitude = ((Number) longitudeObj).doubleValue();
            flightPath.setLongitude(longitude);
        } else {
            throw new RuntimeException("经度字段类型错误，应为数值类型");
        }

        Object altitudeObj = jsonArray.get(3);
        if (altitudeObj == null) {
            log.warn("高度字段类型错误或为空，应为数值类型，忽略该字段: {}", altitudeObj);
            flightPath.setAltitude(null); // 或者设置一个默认值
        } else if (altitudeObj instanceof Number) { // 检查是否为数值类型（包括BigDecimal）
            Double altitude = ((Number) altitudeObj).doubleValue();
            flightPath.setAltitude(altitude);
        } else {
            log.warn("高度字段类型错误或为空，应为数值类型，忽略该字段: {}", altitudeObj);
            flightPath.setAltitude(null); // 或者设置一个默认值
        }

        Object speedObj = jsonArray.get(4);
        if (speedObj instanceof Number){
            Double speed = ((Number) speedObj).doubleValue();
            flightPath.setSpeed(speed);
        }

        Object headingObj = jsonArray.get(5);
        if (headingObj instanceof Number){
            Double heading = ((Number) headingObj).doubleValue();
            flightPath.setHeading(heading);
        }

        String sourceType = null;
        // 判断是否为json格式
        if (jsonArray.get(8) == null){
            flightPath.setSource_type("");
        } else if (jsonArray.get(8) instanceof JSON){
            JSONObject jsonObject1 = JSONUtil.parseObj(jsonArray.get(8));
            if (jsonObject1.getStr("type") == null){
                throw new RuntimeException("原始航迹数据sourceType为空");
            }
            sourceType = jsonObject1.getStr("type");
            flightPath.setSource_type(sourceType);
        }

        log.info("映射后的AirFlightPathDto对象: {}", flightPath); // 输出映射后的AirFlightPathDto对象
        return flightPath;
    }

}